Android 12上焕然一新的小组件:美观、便捷和实用 您所在的位置:网站首页 color widgets图标怎么用 Android 12上焕然一新的小组件:美观、便捷和实用

Android 12上焕然一新的小组件:美观、便捷和实用

2023-12-11 02:26| 来源: 网络整理| 查看: 265

Google IO 2021上重磅介绍的Android 12,号称历代设计变化最大的版本。其全新的Material You设计语言、流畅的动画特效再到焕然一新的小组件,都令人印象深刻。本文将聚焦小组件环节,谈谈它在重新设计之后的各种新特性和适配方法。

小组件在Android平台上命名为AppWidget,有的时候还被翻译成小部件、小插件和微件。说的都是一个东西:显示在Launcher上,能在Logo以外提供更多信息的特别设计。它方便用户免于打开App即可直接查看信息和进行简单的交互,在PC上、早前的Symbian上都有类似的设计。

前言

简要回顾下移动平台在小组件设计上的持续探索:

早期的Android版本缺乏美观,小组件更是常年未改。似乎除了天气、时钟等常用小组件以外鲜少使用,逐渐被人遗忘 Windows Phone的动态磁贴在自由尺寸的Logo上灵活展示信息的设计非常超前,奈何生态构建困难,早已退场 Apple向来稳重(保守),直到iOS 10才引入小组件,但负一屏限制着它的发展。直到iOS 14的全面支持才大获成功,大有后来居上的态势 VIVO紧随其后重磅推出的OriginOS则将Logo和小组件完美融合,试图一统磁贴和小组件的概念,非常值得称赞

也许是受到了友商们的持续刺激,Google终于开始重新审视小组件这个元老级功能,并在Android 12里进行了重新设计、重新出发。

12-widget

下面将结合代码实战,带领大家逐步感受Android 12里小组件的各项新特性和对应的适配方法。

1. 选择和展示的统一变化

事实上即使未做任何适配,在12上直接运行的小组件与11就有明显不同,主要表现在选择器和展示的效果。

以Chrome和Youtube Music的小组件为例:

12-widget-picker

可以看到12上的一些变化:

选择器 顶部悬浮搜索框,可以更加快速地找到目标小组件 小组件按照App自动折叠,避免无关的小组件占用屏幕空间 App标题还对包含的小组件数目进行了提示 拖拽到桌面上之后小组件默认拥有圆角设计

11上的小组件选择器不支持搜索而且无法折叠,拖拽到桌面上也是初始的直角效果。

11-widget-picker 2. 美观的圆角设计

健康信息越发重要,手撸一个展示今日步数的小组件,搭配androidplot框架展示详细的步数图表。

override fun onUpdate(...) { for (appWidgetId in appWidgetIds) { showBarChartToWidget(context, appWidgetManager, appWidgetId) } } private fun showBarChartToWidget(...) { // Create plot view. val plot = XYPlot(context, "Pedometers chart") ... // Set graph shape plot.setBorderStyle(Plot.BorderStyle.ROUNDED, 12f, 12f) plot.isDrawingCacheEnabled = true // Reflect chart's bitmap to widget. val bmp = plot.drawingCache val remoteViews = RemoteViews(context.packageName, R.layout.widget_pedometer) remoteViews.setBitmap(R.id.bar_chart, "setImageBitmap", bmp) appWidgetManager.updateAppWidget(appWidgetId, remoteViews) }

不用特别适配,直接运行到12上,就能有圆角效果。

12-widget

但布局需要遵从如下两点建议:

四周的边角不要放置内容,防止被切掉 背景不要采用透明的、空的视图或布局,避免系统无法探测边界去进行裁切

事实上,系统预设了如下dimension以设置默认的圆角表现。

system_app_widget_background_radius: 小组件背景的圆角尺寸,默认16dp,上限28dp system_app_widget_inner_radius: 小组件内部视图的圆角尺寸 ,默认8dp,上限20dp system_app_widget_internal_padding:内部视图的padding值,默认16dp

看下官方的对于内外圆角尺寸的示意图。

12-widget

注意:

这些dimension可以被ROM厂商或3rd Launcher修改,不一定能保证一致性的尺寸 官方没有说明小组件的内部视图如何才能应用上内部圆角尺寸,DEMO确实也没有适配上,不知道是ROM的问题还是App的问题,有待后续的进一步研究

当然12以前的系统想要支持圆角设计也很简单:自定义radius的attribute,应用在shape drawable上,手动将drawable应用到background。具体可参考官方Sample:

github.com/android/use…

3. 动态的色彩效果

给小组件添加暗黑主题支持即可自动适配动态色彩。

@color/purple_500 @color/purple_700 @color/white ... @color/purple_200 @color/purple_700 @color/black ... 12-widget 4. 改进的小组件预览

12针对小组件选择时的预览界面进行了改进,方便展示更加精准的预览效果。

4.1 动态预览

之前只能使用previewImage属性展示一张预览图,功能迭代的过程中忘记更新它的话,可能导致预览和实际效果发生偏差。

12新引入了previewLayout属性用以配置小组件的实际布局,使得用户能够在小组件的选择器里看到更加接近实际效果的视图,而不再是一层不变的静态图片。

这样一来在保证效果一致的同时免去了额外维护预览图的麻烦。

既存的图片属性指定UI提供的设计图 --> android:previewImage="@drawable/app_widget_pedometer_preview_2" android:previewLayout="@layout/widget_pedometer"

左边是步数小组件一开始的设计图,右边是最后的实际效果。

在这里插入图片描述

如果忘记说服UI重新作图的话,在11上的预览图会和实际效果有较大偏差。而12上不用在乎设计图是否更新,借助新的API即可直接预览实际效果,所见即所得。

在这里插入图片描述

一般来说previewLayout属性最好指定小组件的实际布局。但如果预览的测试数据和实际的默认值有冲突的话,可以指定专用的预览布局,只需要确保布局的一致。

4.2 添加预览说明

description属性则可以在小组件预览的下方展示额外的说明,便于用户更好地了解其功能定位。

12-widget

需要提醒的是description属性并非12新增,但12之前的选择器不支持展示这个说明。

5. 支持新的交互控件

之前的小组件不支持CheckBox等控件,从12开始全面支持CheckBox、Switch和RadioButton三种状态控件。

下面是采用这三种控件的简单效果。

12-widget

再做个简单的待办事项以更好地说明状态小组件的使用。

// 小组件件布局里指定CheckBox控件即可 ... 12-widget

如果将同样的代码运行到11上,则会显示加载失败。

日志

AppWidgetHostView: Error inflating AppWidget AppWidgetProviderInfo(UserHandle{0}/ComponentInfo{com.example.splash/com.example.splash.widget.TodoListAppWidget}): android.view.InflateException: Binary XML file line #13 in com.example.splash:layout/widget_todo_list: Binary XML file line #13 in com.example.splash:layout/widget_todo_list: Error inflating class android.widget.CheckBox

12以前的小部件不支持展示CheckBox等控件

文本内容不确定的话,可以通过代码动态地控制文本,同时还可以监听用户的选择事件。

比如我们要展示Android开发者如今要学习的三座大山,选中的时候弹出Toast。

private fun updateAppWidget(...) { val viewId1 = R.id.checkbox_first val pendingIntent = PendingIntent.getBroadcast(...) val rv = RemoteViews(context.packageName, R.layout.widget_todo_list) rv.apply { // 设置文本 setTextViewText(viewId1, context.resources.getString(R.string.todo_list_android)) ... // 设置CheckBox的默认选中状态 setCompoundButtonChecked(viewId1, true) // 监听相应的CheckBox的选中事件 setOnCheckedChangeResponse( viewId1, RemoteViews.RemoteResponse.fromPendingIntent(pendingIntent) ) } appWidgetManager.updateAppWidget(appWidgetId, remoteViews) } override fun onReceive(context: Context?, intent: Intent?) { ... val checked = intent.extras?.getBoolean(RemoteViews.EXTRA_CHECKED, false) ?: false val viewId = intent.extras?.getInt(EXTRA_VIEW_ID) ?: -1 Toast.makeText( context, "ViewId : $viewId's checked status is now : $checked", Toast.LENGTH_SHORT ).show() } 12-widget 6. 便捷地配置尺寸

12针对小组件的尺寸配置环节也进行了改进,更加便捷。

6.1 精确的尺寸

在已有的minWidth、minResizeWidth等属性以外,新增了几个属性以更便捷地配置小组件的尺寸。

targetCellWidth和targetCellHeight:占据Launcher上Cell的宽高格数,用以替代minWidth和minHeight。事实上Launcher是以Cell的单位来展示小组件的,所以直接指定Cell数显然更合理 maxResizeWidth和maxResizeHeight: 配置Launcher上允许配置的最大尺寸,弥补minResizeWidth和minResizeHeight的不足 CheckBox精准布局预览 6.2 灵活调节尺寸

iOS上添加小组件后尺寸就固定了,不支持调节。而Android 12上小组件在长按后即可灵活调节。

CheckBox长按效果

想要支持这个特性只需要给widgetFeatures属性指定reconfigurable值即可。

The reconfigurable flag was introduced in Android 9 (API level 28), but it was not widely supported in launchers until Android 12.

事实上这个属性早在Android 9的时候就引入了,但官方说从S开始才全面支持。我在11版本的Pixel Launcher上发现已经可以直接调节尺寸了,不知道官方的意思是不是别的Launcher并不支持。

6.3 采用默认配置

configure属性可以在小组件展示之前启动一个配置画面,供用户选择小组件所需的内容、主题和风格等。

如果想让用户快速看到效果,即不想展示这个画面的话,只要在widgetFeatures里指定新的configuration_optional值即可。

后面改主意了又想替换配置的话,可以长按小组件找到配置的入口。

一是小组件右下方的编辑按钮,二是上方出现的Setup菜单,这在以前的版本上是没有的。

12-widget 7. 高效地控制布局

小组件内容较多的时候,为了展示的完整往往会给它限定Size,这意味着只有Launcher空间足够大小组件才能成功放置。当Launcher空间捉急的时候就尴尬了,用户只能在移除别的小组件和放弃你的小组件之间做个抉择。

免除这种困扰的最佳做法是在不同的Size下采用不同的布局,对展示的内容做出取舍。即Size充足的情况下提供更多丰富的内容,反之只呈现最基本、最常用的信息。

7.1 响应式布局

之前是如何做到这一需求呢?除了预设各种尺寸的小组件的一般思路以外,通过onAppWidgetOptionsChanged回调也可以控制布局的变化,但往往非常繁琐。

而12上借助新增的RemoteViews(Map map)API可以大大简化实现过程。在小组件放置的时候就将Size和布局的映射关系告知系统,当Size变化了AppWidgetManager将自动响应更新对应的布局。

比如待办事项小组件在Size为3x2的时候额外展示添加按钮,2x2的时候只展示事项列表的相应式布局。

12-widget

代码的实现也简单清晰:

private fun updateAppWidgetWithResponsiveLayouts(...) { ... // 尺寸够宽的情况下Button才显示 val wideView = RemoteViews(rv) wideView.setViewVisibility(button, View.VISIBLE) val viewMapping: Map = mapOf( SizeF(100f, 100f) to rv, SizeF(200f, 100f) to wideView ) // 将Size和RemoteViews布局的映射关系告知AppWidgetManager val remoteViews = RemoteViews(viewMapping) appWidgetManager.updateAppWidget(appWidgetId, remoteViews) }

好处:

免于同一功能提供一堆尺寸小组件的繁琐,减轻选择器的负担 实现简单,自动响应 7.2 精确布局

如今移动设备的尺寸、形态丰富多样,尤其是折叠屏愈加成熟。如果响应式布局仍不能满足更精细的需求,可以在Size变化的回调里,获取目标Size对布局进一步的精确把控。

利用AppWidgetManager新增的OPTION_APPWIDGET_SIZES KEY可以从AppWidgetManager里拿到目标Size。

// 监听目标尺寸 override fun onAppWidgetOptionsChanged(...) { ... // Get the new sizes. val sizes = newOptions?.getParcelableArrayList( AppWidgetManager.OPTION_APPWIDGET_SIZES ) // Do nothing if sizes is not provided by the launcher. if (sizes.isNullOrEmpty()) { return } Log.d("Widget", "PedometerAppWidget#onAppWidgetOptionsChanged() size:${sizes}") // Get exact layout if (BuildCompat.isAtLeastS()) { val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews)) appWidgetManager?.updateAppWidget(appWidgetId, remoteViews) } }

如下的日志显示Size变化的时候会将目标Size回传。

Widget : PedometerAppWidget#onAppWidgetOptionsChanged() size:[377.42856x132.0, 214.57143x216.57143]

之后从预设的精细布局里匹配相应的视图。

private fun createRemoteViews(size: SizeF): RemoteViews { val smallView: RemoteViews = ... val tallView: RemoteViews = ... val wideView: RemoteViews = ... ... return when (size) { SizeF(100f, 100f) -> smallView SizeF(100f, 200f) -> tallView SizeF(200f, 100f) -> wideView ... } }

注意:实际上Size列表由Launcher提供,如果3rd Launcher没有适配这一特性的话,回传的Size可能为空

8. 自由地更新视图

RemoteViews作为小组件视图的重要管理类,本次OSV也添加了诸多API,以便更加自由地控制视图的展示。

更改颜色的setColorStateList() 更改边距的setViewLayoutMargin() 更改宽高的setViewLayoutWidth()等

这些新API可以助力我们实很多方便的功能,比如CheckBox选中之后更新文本颜色,思路很简单:

监听小组件的点击事件并传递目标视图 根据CheckBox的状态获得预设的文本颜色 使用setColorStateList()更新 override fun onReceive(context: Context?, intent: Intent?) { ... // Get target widget. val appWidgetManager = AppWidgetManager.getInstance(context) val thisAppWidget = ComponentName(context!!.packageName, TodoListAppWidget::class.java.name) val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget) // Update widget color parameters dynamically. for (appWidgetId in appWidgetIds) { val remoteViews = RemoteViews(context.packageName, R.layout.widget_todo_list) remoteViews.setColorStateList( viewId, "setTextColor", getColorStateList(context, checked) ) appWidgetManager.updateAppWidget(appWidgetId, remoteViews) } } private fun getColorStateList(context: Context, checkStatus: Boolean): ColorStateList = if (checkStatus) ColorStateList.valueOf(context.getColor(R.color.widget_checked_text_color)) else ColorStateList.valueOf(context.getColor(R.color.widget_unchecked_text_color)) 12-widget

再比如Chart线图太小,看不清楚。可以让它在点击之后放大,再点击之后恢复原样。

// 根据记录的缩放状态获得预设的宽高 // 通过setViewLayoutWidth和setViewLayoutHeight更新宽高 override fun onReceive(context: Context?, intent: Intent?) { ... val widthScaleSize = if (scaleOutStatus) 200f else 260f val heightScaleSize = if (scaleOutStatus) 130f else 160f // Update widget layout parameters dynamically. for (appWidgetId in appWidgetIds) { val remoteViews = RemoteViews(context.packageName, R.layout.widget_pedometer) remoteViews.setViewLayoutWidth(viewId, widthScaleSize, TypedValue.COMPLEX_UNIT_DIP) remoteViews.setViewLayoutHeight(viewId, heightScaleSize, TypedValue.COMPLEX_UNIT_DIP) appWidgetManager.updateAppWidget(appWidgetId, remoteViews) } } 12-widget 9. 流畅的启动效果

12版本上点击Widget启动App的时候可以呈现更流畅的过渡效果,适配也很简单。官方指示只需给小组件的根布局指定android的 backgoround id即可。

实际的动作显示添加这个ID后App启动没有什么变化,个中原因需要继续研究。

12开始对从Broadcast Receiver或Serivce启动Activity做了更严格的限制,但不包括Widget发起的场合。但为了避免视觉上的突兀,这种后台启动的情况下不展示迁移动画。

10. 简化的数据绑定

小组件里展示ListView的需求也很常见,提供数据的话需要声明一个 RemoteViewsService 以返回RemoteViewsFactory,比较绕。

而12里新增的 setRemoteAdapter(int , RemoteCollectionItems) API则可以大大简化这个绑定过程。

比如制作一个即将到来的事件列表小组件,通过这个API便可以高效注入数据。

private fun updateCountDownList(...) { ... // 创建用于构建Remote集合数据的Builder val builder = RemoteViews.RemoteCollectionItems.Builder() val menuResources = context.resources.obtainTypedArray(R.array.count_down_list_titles) // 往Builder里添加各Item对应的RemoteViews for (index in 0 until menuResources.length()) { ... builder.addItem(index.toLong(), constructRemoteViews(context, resId)) } // 构建Remote集合数据 // 并通过setRemoteAdapter直接放入到ListView里 val collectionItems = builder.setHasStableIds(true).build() remoteViews.setRemoteAdapter(R.id.count_down_list, collectionItems) ... } // 创建ListView各Item对应的RemoteViews private fun constructRemoteViews(...): RemoteViews { val remoteViews = RemoteViews(context.packageName, R.layout.item_count_down) val itemData = context.resources.getStringArray(stringArrayId) // 遍历Item数据行设置对应的文本 itemData.forEachIndexed { index, value -> val viewId = when (index) { 0 -> R.id.item_title 1 -> R.id.item_time ... } remoteViews.setTextViewText(viewId, value) } return remoteViews } CheckBox精准布局预览

如果Item的布局不固定不止一种,可以使用setViewTypeCount指定布局类型的数目,告知ListView需要提供的ViewHolder种类。如果不指定也可以,系统将自动识别布局的种类,需要系统额外处理而已。

但要注意:如果指定的数目和实际的不一致会引发异常。

IllegalArgumentException: View type count is set to 2, but the collection contains 3 different layout ids

另外,需要补充一下,支持该API的View必须是AdapterView的子类,比如常见的ListView、GridView等。RecyclerView是不支持的,毕竟小组件里数据量不多,不能使用也没关系。

11. 新增API总结

简要罗列一下12针对小组件新增的API,方便大家查阅。

RemoteViews类 方法作用RemoteViews(Map)根据响应式布局映射表创建目标RemoteViewsaddStableView()向RemoteViews动态添加子View,类似ViewGroup#addView()setCompoundButtonChecked()针对CheckBox或Switch控件更新选中状态setRadioGroupChecked()针对RadioButton控件更新选中状态setRemoteAdapter(int , RemoteCollectionItems)直接将数据填充进小组件的ListViewsetColorStateList()动态更新小组件视图的颜色setViewLayoutMargin()动态更新小组件视图的边距setViewLayoutWidth()、setViewLayoutHeight()动态更新小组件视图的宽高setOnCheckedChangeResponse()监听CheckBox等三种状态小组件的状态变化 XML属性 属性作用description配置小组件在选择器里的补充描述previewLayout配置小组件的预览布局reconfigurable指定小组件的尺寸支持直接调节configuration_optional指定小组件的内容可以采用默认设计,无需启动配置画面targetCellWidth、targetCellHeight限定小组件所占的Launcher单元格maxResizeWidth、maxResizeHeight配置小组件所能支持的最大高宽尺寸 结语

通过上面的解读,大家可以感受到Google在小组件的重新设计上耗费了诸多努力,它给这个老旧的功能注入很多新玩法和新花样。

简要回顾一下Android 12里小组件的新特性:

更便捷的小组件选择器 更美观的圆角边框设计 更灵活的小组件预览 更完整的控件支持 更方便的尺寸调节 更精准的布局控制 更自由的视图更新 更简便的列表数据绑定

如此之多的新特性,在助力小组件高效开发的同时,还能给用户呈现更加优秀的使用体验。

跟随Android 12的脚步,快快尝试起来,让现有的小组件重新绽放光彩。

未决事项 小组件内部视图的圆角尺寸如何适配? 小组件启动App的流畅过渡效果如何实现,是什么效果? 本文DEMO

NewAppWidget

参考文档

官方宣传

官方介绍文档

官方Sample

推荐阅读

Android 12上全新的应用启动画面,还不适配一下?

全面复盘Android开发者容易忽视的Backup功能。

为什么推荐使用CameraX?



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有